package archer.framework.utils;

import archer.framework.core.exception.BaseException;
import jodd.bean.BeanUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * 结构化工具类
 *
 * @author christ
 * @date 2016/9/2
 */
public class Functional {

    private static Logger logger = LoggerFactory.getLogger(Functional.class);

    private static BeanUtil pojo = BeanUtil.pojo;

    /**
     * 求和
     *
     * @param src
     * @param clazz
     * @param fields
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> E sum(List<T> src, Class<E> clazz, String... fields) {

        return sum(src, newInstance(clazz), fields);
    }

    public static <T, E> E sum(List<T> src, E target, String... fields) {

        if (ValidateUtils.isEmpty(src)) {
            return target;
        }

        for (T each : src) {
            for (String field : fields) {
                BigDecimal targetValue = pojo.getProperty(target, field);
                BigDecimal srcValue = pojo.getProperty(each, field);
                pojo.setProperty(target, field, BigDecimalUtils.add(targetValue, srcValue));
            }
        }
        return target;
    }

    /**
     * 求和
     *
     * @param src
     * @param field
     * @param <T>
     * @return
     */
    public static <T> BigDecimal sum(List<T> src, String field) {

        return sum(src, field, src.size());
    }

    /**
     * 调整集合除法计算结果
     *
     * @param src
     * @param amount
     * @param field
     * @param <T>
     * @return
     */
    public static <T> List<T> adjustDivideResult(List<T> src, String field, BigDecimal amount) {

        if (ValidateUtils.isEmpty(src)) {
            return src;
        }

        if (src.size() == 1) {
            pojo.setProperty(src.get(src.size() - 1), field, amount);
        }

        BigDecimal per = sum(src, field, src.size() - 1);

        pojo.setProperty(src.get(src.size() - 1), field, BigDecimalUtils.subtract(amount, per));

        return src;
    }

    /**
     * 调整集合除法计算结果
     *
     * @param src
     * @param amount
     * @param <T>
     * @return
     */
    public static <T> List<T> adjustDivideResult(List<T> src, Map<String, BigDecimal> amount) {

        for (Map.Entry<String, BigDecimal> entry : amount.entrySet()) {
            adjustDivideResult(src, entry.getKey(), entry.getValue());
        }

        return src;
    }


    /**
     * 求和
     *
     * @param src
     * @param field
     * @param <T>
     * @return
     */
    private static <T> BigDecimal sum(List<T> src, String field, int cursor) {

        BigDecimal result = BigDecimal.ZERO;

        if (ValidateUtils.isEmpty(src)) {
            return result;
        }

        for (int i = 0; i < cursor; i++) {
            result = BigDecimalUtils.add((BigDecimal) pojo.getProperty(src.get(i), field), result);
        }
        return result;
    }

    /**
     * 打印某些字段
     *
     * @param src
     * @param fields
     * @param <T>
     */
    public static <T> void println(List<T> src, String... fields) {

        if (ValidateUtils.isNotEmpty(src)) {
            for (T each : src) {
                for (String field : fields) {
                    System.out.println(pojo.getProperty(each, field));
                }
                System.out.println();
            }
        }
    }

    /**
     * json输出
     *
     * @param src
     * @param <T>
     */
    public static <T> void jsonPrintln(List<T> src) {

        System.out.println(JSONUtils.serialize(src));
    }

    /**
     * 创建实例
     *
     * @param clazz
     * @param <T>
     * @return
     */

    private static <T> T newInstance(Class<T> clazz) {
        try {
            return (T) ReflectUtils.newInstance(clazz);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BaseException(e);
        }
    }
}
